"""
Feed utility functions
"""
from django.db import connection
from westom.feednut.models import *
from westom.feednut.libs import feedparser
import time
from datetime import datetime
from westom.feednut.utils import misc as misc_utils
from westom.feednut.utils import feed_utils
from westom.settings import URL_HOST
import re, random
import logging

def get_feeds(xml_url=None, user=None, tags=None, only_public=None, default_feed=None, permanent_feed=None, limit=None):
    """
    Returns a list of Feed objects matching the criteria in the parameters.
    
    If a feed cannot be found and the xml_url is given, try to download that feed and return it.
    """
    if tags and user and 'fn:untagged' in tags:
        cursor = connection.cursor()
        cursor.execute("""
            select feednut_feed.* from
            (feednut_userfeed uf left join feednut_userfeedtag uft on uf.id=uft.user_feed_id)
                left join feednut_feed on uf.feed_id = feednut_feed.id
            where uf.user_id=%s
                  and uft.user_feed_id is null""" % user.id)
        feeds = [Feed(*row) for row in cursor.fetchall()]
        return feeds
    
    elif tags and 'fn:all' in tags:
        tags=None
    
    elif tags and 'fn:private' in tags:
        only_public=False
    
        
    feeds = []
    where = []
    tables = []
    params = []
    
    if xml_url:
        xml_url = xml_url.strip().lower()
        if not xml_url.startswith('http'):
            xml_url = 'http://%s' % xml_url
        where.append('feednut_feed.xml_url=%s')
        params.append(xml_url)
    
    #if you are filtering with user, tag, only_public or permanent_feed then you will need the userfeed table
    if user or tags or only_public or permanent_feed:
        where.append('feednut_feed.id=feednut_userfeed.feed_id')
        tables.append('feednut_userfeed')
        
    if user:
        where.append('feednut_userfeed.user_id=%s')
        params.append(user.id)
        
    if tags:
        where.extend(['feednut_tag.tag in (%s)',
                     'feednut_userfeedtag.user_feed_id=feednut_userfeed.id',
                     'feednut_userfeedtag.tag_id=feednut_tag.id'])
        tables.extend(['feednut_tag', 'feednut_userfeedtag'])
        params.append(','.join(tags))
        
    if only_public != None:
        where.append('feednut_userfeed.is_public=%s')
        params.append(only_public)
    
    if permanent_feed is not None:
        where.append('feednut_userfeed.permanent_feed=%s')
        params.append(permanent_feed)
   
    if default_feed != None:
        where.append('feednut_feed.default_feed=%s')
        params.append(default_feed)
        
    #print "where: ", where
    #print "tables: ", tables
    #print "params: ", params
    
    feeds = Feed.objects.extra(where=where, tables=tables, params=params).distinct()[:limit]
    
    if not feeds and xml_url:
        feeds = get_feed(url)
        
    return(feeds)

def get_feed(url):
    """
    Gets the Feed for the given URL.
    
    If it doesn't exist yet, the feed is downloaded and added to the Feeds table.
    The new Feed is returned, or None if there was an error.
    """
    #first, see if it already exists
    url = url.strip().lower()
    if not url.startswith('http'):
        url = 'http://%s' % url
    try:
        feed = Feed.objects.get(xml_url__iexact=url)
    except:
        return updatefeed(url)
    else:
        return feed

def get_system_feed(url):
    """
    Gets the special system Feed for the given URL.
    
    If it doesn't exist yet, 
    """
    #first, see if it already exists
    url = url.strip().lower()
    if not url.startswith('http'):
        url = 'http://%s' % url
    try:
        feed = Feed.objects.get(xml_url__iexact=url)
    except:
        return add_system_feed(url)
    else:
        return feed

def add_system_feed(xml_url):
    """
    Create a special system feed. These are the feeds generated by feednut.com
    """
    xml_url = xml_url.strip().lower()
    if not xml_url.startswith('http'):
        xml_url = 'http://%s' % xml_url
        
    feed = Feed(xml_url=xml_url, title='', create_date = datetime.now(), last_modified = datetime.now())
    feed.save()
    
    feed = get_feed(xml_url)
    
    return(feed)

 
def updatefeed(url):
    """
    This attempts to download the feed at the given URL and either:
        - update the currently existing Feed instance
        - Create a new Feed instance
    Returns the Feed, or None
    """
    if type(url) == str:
        return feed_utils.get_feed(url, index=True, update=True)
    else:
        feed = url
        return feed_utils.get_feed(feed.xml_url, last_modified=(feed.last_modified or None), index=True, update=True)


def add_userfeed(user_or_id, feed_or_id, tags=[], permanent_feed=False):
    """
    Add a userfeed by taking in the user and feed, and optional
    positional parameters and tags
    """
    user = user_or_id
    if type(user) == str:
        user = User.objects.get(id=user)
    
    feed = feed_or_id
    if type(feed) == str:
        feed = Feed.objects.get(pk=feed)
    
    userfeed = None
    if feed:
        #make sure it doesn't already exist
        try:
            userfeed = UserFeed.objects.get(user__id__exact=user.id, feed__id__exact=feed.id)
        except:
            #create it!
            feed = get_feed(feed.xml_url)
            userfeed = UserFeed(user=user, feed=feed, create_date=datetime.now())
            userfeed.save()

        if tags:
            tag_feed(userfeed, tags)
        
        if permanent_feed:
            userfeed.permanent_feed = True
            userfeed.save()
        
    return userfeed


#VALID_TAG = re.compile(r'^\w+$')
def tag_feed(userfeed_or_id, tagnames=[]):
    """
    Takes a userfeed or userfeed.id and a list of tags
    and adds those tags for the userfeed.
    
    The tags are created if they don't exist already.
    
    Note:* Also, any tags the user already has for this feed that
    are not included in tagnames are removed.
    """
    userfeed = userfeed_or_id
    if type(userfeed) == str:
        userfeed = UserFeed.objects.get(id=userfeed)
    
    #get users current tags
    curtags = dict((userfeedtag.tag.tag.lower(), userfeedtag) for userfeedtag in userfeed.userfeedtag_set.all())
    print 'CURTAGS:', curtags
    
    #loop over new tagnames
    for name in tagnames:
        name = name.strip().lower()[:20]
        if len(name) == 0:
            continue
        
        if name == 'fn:untagged':
            continue
        
        if name == 'fn:private':
            userfeed.is_public = False
            userfeed.save()
        
        if not curtags.has_key(name):
            #see if we need to add a new tag
            try:
                tag = Tag.objects.get(tag__iexact=name)
            except:
                tag = Tag(tag=name)
                tag.save()
            userfeedtag = UserFeedTag(user_feed=userfeed, tag=tag)
            try:
                userfeedtag.save()
            except:
                pass #already tagged with this tag
        else:
            #otherwise, we already have it, so pop it so we dont delete it
            curtags.pop(name, None)
    
    #now, delete the old tags the user no longer has
    for userfeedtag in curtags.values():
        userfeedtag.delete()
    

def update_feeds():
    """
    Run through the entire list of Feeds and:
        - download the latest feed, if it has been updated
        - update the feed in the database
    """
    
    feed_ids = [f['feed'] for f in UserFeed.objects.select_related().values('feed').distinct()]
    for id in feed_ids:
        try:
            feed = Feed.objects.get(id=id)
            updatefeed(feed)
        except:{}


def add_permanent_feeds(user):
    permanent_feeds = [('%s/latest.rss' % URL_HOST,  ['fn:home', 'fn:recentread']),
           ('%s/hottest.rss' % URL_HOST,  ['fn:home', 'fn:hottestfeed']),
           ('%s/%s/latest.rss' % (URL_HOST, user.username), ['fn:recentread']),
           ('%s/%s/hottest.rss' % (URL_HOST, user.username), ['fn:hottestfeed']),
           ('%s/%s/readlater.rss' % (URL_HOST, user.username), ['fn:readlater'])]
                    
    for permanent_feed in permanent_feeds:
        feed = get_system_feed(permanent_feed[0])
        #print "feed: ", feed
        feed.system_feed = True
        feed.save()
        
        add_userfeed(user, feed, tags=permanent_feed[1], permanent_feed=True)
        
#def get_default_feeds():
#    return get_feeds(user=user, default_feed=True)


##### Entry functions for Feeds ####
def push_entry(feed_or_id, title=None, link=None, description=None, xml_url=None):
    """ Add a new Entry to this Feed, deleting the oldest Entry if necessary. """
    
    feed = feed_or_id
    if type(feed) == str:
        feed = Feed.objects.get(id=feed)
    
    #this is like a fixed size queue, push an entry onto the back of the queue, and pop one off the top
    entries = get_entries(feed)

    max_entries = 25
    for entry in entries[max_entries-1:len(entries)]:
        entry.delete()
        
    #if len(entries) == 10:
    #    entries[-1].delete()
    
    entry = Entry(feed_id=feed.id, title=title, link=link, description=description, xml_url=xml_url)
    entry.save()


def get_entries(feed_or_id):
    """ Get all the Entry's for this Feed """
    feed = feed_or_id
    if type(feed) == str:
        feed = Feed.objects.get(id=feed)
    
    entries = feed.entry_set.order_by('-create_date')
    
    return entries

